/**
 * @file cutility.c
 * @brief Comandi d'utilità dell'applicativo.
 *
 * @date Feb 27, 2012
 * @author: Francesco Corvino
 */
#include "cutility.h"
#include <unistd.h>
#include "../invoker.h"
#include "../envFactory.h"
#include "../../RscHost/rscApplication.h"
#include "../../RscHost/factoryComm.h"
#include "../../logproxy/logproxy.h"
#include "../../RscNet/rscNet.h"

/**
 * @brief Implemeta il comando help.
 *
 * Permette di stampare tutti i comandi registrati nell'applicazione.
 */
void exGetsAllCommands(){
	int i;
	DynArray* commands = RscApp_getCommands();
	AppLib_writeToHostF("Comandi registrati[%d]:\n",commands->numelement);

	log_namedlevel(CUTILITY_LOGNAME,LOG_DEBUG_LEVEL,
			"Avvio comando help, scrittura di %d comandi",commands->numelement);

	for(i=0;i< commands->numelement;i++){
		InterfaceCommand *cmd = (InterfaceCommand*) DynArray_getIndex(commands,i);
		char* outInfo = (char*) HiddenType_executeInterpreter(&(cmd->descriptorInfo),NULL);
		AppLib_writeToHostF( "%d * %s : %s \n", i,cmd->name,
				(outInfo==NULL)?("<<No info>>"):(outInfo));
	}
}

/**
 * @brief Effettua la chiusura del programma.
 */
void exCloseProgram(){
	AppLib_writeToHost("Avvio procedura di terminazione");
	AppLib_terminate();
}

/**
 * @brief Comando che restituisce le informazioni sulle sessioni.
 *
 * Restitusce le informazioni sulle sessioni attive e sulle elaborazioni
 * presenti per ogni sessione. La sessione in cui viene lanciato il comando dovrà contenere
 * almeno l'elaborazione relativa allo stesso comando.
 */
void exGetSessions(){
	int i;
	CMap* arr = RscApp_getAllSession();
	AppLib_writeToHostF("Sessioni presenti: %d\n",arr->values.numelement);
	for(i=0; i < arr->values.numelement;i++){
		HostSession *session = (HostSession*) CMap_getByIndex(arr,i);
		int numElab = session->threadsForSession.numelement;
		AppLib_writeToHostF("- Sessione %d -> %d threads attive",
				session->keySession, numElab);
		if(numElab!=0) {
			int iE = 0; DynArray* elabs = &(session->threadsForSession);
			AppLib_writeToHost(", tid associati:");
			for(iE = 0;iE<numElab;iE++){
				int key = ((ElaborationEntity*) DynArray_getIndex(elabs,iE))->keyElaboration;
				AppLib_writeToHostF(" (%d - %d);",iE,key);
			}
		}
		AppLib_writeToHost("\n");
	}
}

void exSleep(){
	char msg[30];
	do{
		AppLib_readFromHost(msg,30);
		AppLib_writeToHostF("Hai scritto <%s> \n",msg);
	} while(strncmp(msg,"end",3)!=0);
}

void exNewTerminal(){
	pid_t pid;
    if ((pid = fork()) < 0) {
    	AppLib_writeToHost("Errore nel creare la nuova sessione!\n");
    } else if (pid == 0) {      /* child */
    	execlp("./launchTerminal", (char *)0);
    	exit(0);
    }
    AppLib_writeToHost("Avviata una nuova sessione!\n");
}

/**
 * @brief Comando che termina la sessione corrente.
 */
void exEnd(){
	char sessionStr[10];
	HostSession* session = NULL;
	/// - controlla se è stata specificata una sessione da eliminare
	if(AppLib_getParam("key",sessionStr, 10)>0){
		/// + ricava la chiave della sessione da chiudere
		int key = atoi(sessionStr);
		/// + ricava la sessione da chiudere
		session = FactComm_getSession(key);
		/// + controlla se la sessione è valida
		if (session == NULL) {
			AppLib_writeToHost("Si è verificato un'errore: la sessione non esiste!\n");
			return ;
		}
		/// + richiede alla factoryComm di rimuovere la sessione
		FactComm_deleteSession(session);
	} else {
		session = AppLib_getMySession();
		AppLib_writeToHostF("Chiusura della sessione %d..",session->keySession);
		AppLib_closeMySession();
	}
}

void exReport(){
	int i =0;ConnectionInfo *temp = NULL;
	DynArray *arr = RscNet_getConnections();
	DYNARRAY_FOREACH(arr,&i,temp){
		if(temp==NULL) continue;
		Connection *c = temp->c;
		AppLib_writeToHostF(
				"Connessione con %s:%s -> Ricevuti %d byte / %d pkt, Inviati: %d byte / %d pkt\n",
				c->address, c->port,
				c->recvbytes,c->recvpkt,
				c->sendbytes, c->sendpkt);
	}
	if(i==0)
		AppLib_writeToHost("Nessuna connessione monitorata!\n");
}

#define NUM_COMMAND_DEFINED 9

SimpleDescCommand defcmd[] = {
		{"help","Fornisce le informazioni sui comandi disponibili.\0",exGetsAllCommands},
		{"exit","Esce dall'applicazione.\0",exCloseProgram},
		{"sessions","Visualizza le sessioni registrate in memoria.\0",exGetSessions},
		{"chat","Avvia l'esecuzione di una chat.\0",exChat_Start},
		{"chatConfig","Permette di configurare le impostazioni sulla chat.\0",exChat_Configure},
		{"getUsers","Aggiorna gli utenti disponibili per una chat.\0",exChat_Update},
		{"end","Termina la sessione corrente.\0",exEnd},
		//{"sleep","Avvia una thread dormiente.\0",exSleep},
		{"newTerminal","Avvia un nuovo terminale per comunicare con il processo.\0", exNewTerminal},
		{"report","Elenca lo stato delle connessioni registrate.\0", exReport}
};

/**
 * @brief Funzione pubblica che permette di caricare tutti i comandi definiti per la libreria.
 */
void cutility_load(){
	int i;
	/// Inizializza i valori dei comandi da aggiungere
	for(i=0;i<NUM_COMMAND_DEFINED;i++){
		InterfaceCommand regcmd;
		Command_initBySimpleDef(&regcmd,&defcmd[i]);
		envFact_registerCMD(&regcmd);
	}
}


